#include "Barbarian.h"
#include "../Util.h"
#include <iomanip>

Barbarian::Barbarian(std::string name, std::string race, bool is_male, bool hostile, Progress::ach killAch, int voice_pitch, int level, int exp_since_level_up):
Character(name,race, is_male, killAch, voice_pitch, level, exp_since_level_up, hostile)
{
	setInitialAttributes();
	addExperience(exp, false);
}

void Barbarian::sleep(){
	HP = getMaxHP();
	stamina = getMaxStamina();
	speak("I have slept well. I recovered my health and stamina", this);
}

void Barbarian::gather(bool mana){
	int gathered = ((getConsumption(false)*2) - 5);
	std::string say = name;
	say += " gathered ";
	say += std::to_string(gathered);
	say += " stamina points.";
	speak(say);
	updateStamina(gathered);
}

int Barbarian::getConsumption(bool mag){
		return getAtk()/2;
}

int Barbarian::doAttack(bool mag)
{	
	if(getStamina() - getConsumption(false) < 0){
		speak("I do not have enough stamina to attack", this);
		return -1;
	}
	updateStamina(-getConsumption(false));
	return (getAtk() + (((rand()%(getAtk()*2)) - getAtk()) % getAtk()/4));
}

int Barbarian::attackPossible(){
	std::vector<int> type;
	if(getStamina() - getConsumption(false)> 0){
		type.push_back(1);
	}
	if(type.size() == 0){
		type.push_back(3);
	}
	return type[rand() % type.size()];
}

void Barbarian::getStatus(){
	
	std::string say = name;
	say += " have ";
	say += std::to_string(getHP());
	say += " health points and ";
	say += std::to_string(getStamina());
	say += " stamina points."; 
	speak(say);
}

void Barbarian::getStatusAllAttributes(){
	std::stringstream ss;
	std::string say = name;
	say += " are a ";
	if(male){
		say += "male ";
	}
	else{
		say += "female ";
	}
	say += race;
	say += " barbarian.";
	say += "\n";
	
	say += name;
	say += " have ";
	say += std::to_string(exp);
	say += " experience and are at level ";
	say += std::to_string(level);
	say += ".\n";
	say += name;
	say += " have:\n";
	
	ss << say;
	std::string hpstring = (std::to_string(getHP()) + " health points");
	size_t width = hpstring.size() +1;
	std::string staminastring = (std::to_string(getStamina()) + " stamina points");
	if(width < staminastring.size() + 1){ width = staminastring.size() +1; }
	std::string defstring = (std::to_string(getDef()) + " defence points");
	if(width < defstring.size() + 1){ width = defstring.size() +1; }
	std::string atkstring = (std::to_string(getAtk()) + " attack points");
	if(width < atkstring.size() + 1){ width = atkstring.size() +1; }
	
	ss << std::left << std::setw(width) << hpstring << "|\t" << std::to_string(getMaxHP()) << " maximum health points" << std::endl;
	ss << std::left << std::setw(width) << staminastring << "|\t" << std::to_string(getMaxStamina()) << " maximum stamina points" << std::endl;
	ss << std::left << std::setw(width) << defstring << "|\t" << std::to_string(getMagDef()) << " magical defence points" << std::endl;
	ss << std::left << std::setw(width) << atkstring << "|" << std::endl;
	
	speak(ss.str());
}

std::vector<cmdalt> Barbarian::get_Battle_alternatives()
{
	std::vector<cmdalt> alternatives;
	{
		// attack
		cmdalt alt;
		alt.first = "attack";
		
		alt.second = {};
		alternatives.push_back(alt);
	}	
	{
		// collect
		cmdalt alt;
		alt.first = "collect";
		alt.second = {"stamina"};
		alternatives.push_back(alt);
	}
	{
		// check status
		cmdalt alt;
		alt.first = "check";
		alt.second = {"status", "enemy"};
		alternatives.push_back(alt);
	}
	{
		// run away
		cmdalt alt;
		alt.first = "run";
		alt.second = {"away"};
		alternatives.push_back(alt);
	}
	{
		// run away
		cmdalt alt;
		alt.first = "help";
		alt.second = {};
		alternatives.push_back(alt);
	}
	return alternatives;
}

int Barbarian::getAtk(){
	return atk + getBonus(0);
}

void Barbarian::setInitialAttributes()
{
	HP = 10;
	maxHP = 10;
	def = 10;
	magDef = 10;
	atk = 10;
	stamina = 10;
	maxStamina = 10;
}



void Barbarian::addAtk(int change)
{
	atk += change;
}

void Barbarian::addMaxStamina(int change)
{
	maxStamina += change;
}

int Barbarian::getMaxStamina(){
	return maxStamina + getBonus(5);
}

void Barbarian::updateStamina(int change)
{
	stamina += change;
	if(stamina > getMaxStamina())
	{
		stamina = getMaxStamina();
	}
}

int Barbarian::getStamina(){
		return stamina + getBonus(5);
}

std::string Barbarian::getType()
{
	return "Barbarian";
}

bool Barbarian::equippable(Item& item)
{
	return true; // TODO probably should be more restrictive
}

void Barbarian::levelUp()
{
	level += 1;
	if(level > 1){
		addMaxHP(10);
		addHP(10);		
		addDef(10);
		addAtk(10);
		addMaxStamina(10);
		updateStamina(10);
	}
	// TODO something more here... change other stuff
}
